﻿using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using EasyCore.Utils.Cryptogram;
using SixLabors.ImageSharp.Drawing;
using EasyCore.App;
using System.Collections.Concurrent;
using System.Reflection;
using System.Security.Cryptography;

namespace EasyCore.Extensions
{
    /// <summary>
    /// 字段串与对象的扩展类
    /// </summary>
    public static class StringExtensions
    {
        /// <summary>
        /// json字符串序列化
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="json"></param>
        /// <returns></returns>
        public static T ToObject<T>(this string json)
        {
            if (string.IsNullOrWhiteSpace(json)) return default;
            json = json.Replace("&nbsp;", "");
            return JsonConvert.DeserializeObject<T>(json);
        }

        /// <summary>
        /// json字符串序列化
        /// </summary>
        /// <param name="json"></param>
        /// <returns></returns>
        public static object ToObject(this string json)
        {
            if (string.IsNullOrWhiteSpace(json)) return null;
            return JsonConvert.DeserializeObject(json);
        }

        /// <summary>
        /// json字符串序列化
        /// </summary>
        /// <param name="json"></param>
        /// <returns></returns>
        public static JObject ToJObject(this string json)
        {
            if (string.IsNullOrWhiteSpace(json)) return JObject.Parse("{}");
            return JObject.Parse(json.Replace("&nbsp;", ""));
        }

        /// <summary>
        /// 对象转json字符串
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="json"></param>
        /// <returns></returns>
        public static string ToJson<T>(this T obj)
        {
            if (obj == null) return string.Empty;
            return JsonConvert.SerializeObject(obj);
        }

        /// <summary>
        /// 字典转对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dict"></param>
        /// <returns></returns>
        public static T DictToObject<T>(this Dictionary<string, string> dict)
        {
            var obj = Activator.CreateInstance(typeof(T));
            if (dict == null || !dict.Any()) return (T)obj;
            foreach (var kvp in dict)
            {
                PropertyInfo propertyInfo = typeof(T).GetProperty(kvp.Key);

                if (propertyInfo != null && propertyInfo.CanWrite)
                {
                    var json = JsonConvert.DeserializeObject(kvp.Value, propertyInfo.PropertyType);
                    propertyInfo.SetValue(obj, json);
                }
            }
            return (T)obj;
        }

        /// <summary>
        /// 并发字典转对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dict"></param>
        /// <returns></returns>
        public static T ConDictToObject<T>(this ConcurrentDictionary<string, string> dict)
        {
            var obj = Activator.CreateInstance(typeof(T));
            if(dict == null || !dict.Any()) return (T)obj;
            foreach (var kvp in dict)
            {
                PropertyInfo propertyInfo = typeof(T).GetProperty(kvp.Key);

                if (propertyInfo != null && propertyInfo.CanWrite)
                {
                    var json = JsonConvert.DeserializeObject(kvp.Value, propertyInfo.PropertyType);
                    propertyInfo.SetValue(obj, json);
                }
            }
            return (T)obj;
        }

        /// <summary>
        /// 对象转字典
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static Dictionary<string, object> ObjectToDict<T>(this T obj)
        {
            return obj.ToJson().ToObject<Dictionary<string, object>>();
        }

        /// <summary>
        /// 对象转字典
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static ConcurrentDictionary<string, string> ObjectToConDict<T>(this T obj)
        {
            var dict = new ConcurrentDictionary<string, string>();
            var props = obj.GetType().GetProperties();
            foreach (var item in props)
            {
                dict[item.Name] = item.GetValue(obj).ToJson();
            }
            return dict;
        }

        /// <summary>
        /// 将流Stream转为byte数组
        /// </summary>
        /// <param name="stream"></param>
        /// <returns></returns>
        public static byte[] ReadToBytes(this Stream stream)
        {
            stream.Seek(0, SeekOrigin.Begin);
            byte[] bytes = new byte[stream.Length];
            stream.ReadExactly(bytes);
            stream.Seek(0, SeekOrigin.Begin);

            return bytes;
        }

        /// <summary>
        /// 将流读为字符串
        /// 注：默认使用UTF-8编码
        /// </summary>
        /// <param name="stream">流</param>
        /// <returns></returns>
        public static async Task<string> ReadToString(this Stream stream)
        {
            return await ReadToString(stream, Encoding.UTF8);
        }

        /// <summary>
        /// 将流读为字符串
        /// 注：使用指定编码
        /// </summary>
        /// <param name="stream">流</param>
        /// <param name="encoding">指定编码</param>
        /// <returns></returns>
        public static async Task<string> ReadToString(this Stream stream, Encoding encoding)
        {
            if (stream.CanSeek)
            {
                stream.Seek(0, SeekOrigin.Begin);
            }

            string resStr = string.Empty;
            resStr = await new StreamReader(stream, encoding).ReadToEndAsync();

            if (stream.CanSeek)
            {
                stream.Seek(0, SeekOrigin.Begin);
            }

            return resStr;
        }

        /// <summary>
        /// 字节转字符串
        /// </summary>
        /// <param name="bytes"></param>
        /// <param name="encoding"></param>
        /// <returns></returns>
        public static string ByteToString(this byte[] bytes, Encoding encoding = null)
        {
            if (bytes == null)
            {
                return String.Empty;
            }
            else
            {
                if (encoding == null)
                {
                    encoding = Encoding.UTF8;
                }
                return encoding.GetString(bytes);
            }
        }

        /// <summary>
        /// 字符串转字节
        /// </summary>
        /// <param name="str"></param>
        /// <param name="encoding"></param>
        /// <returns></returns>
        public static byte[] StringToBytes(this string str, Encoding encoding = null)
        {
            if (str == null)
            {
                str = String.Empty;
            }
            if (encoding == null)
            {
                encoding = Encoding.UTF8;
            }
            return encoding.GetBytes(str);
        }

        /// <summary>
        /// 对象转字节
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <param name="encoding"></param>
        /// <returns></returns>
        public static byte[] ObjectToBytes<T>(this T obj, Encoding encoding = null)
        {
            return obj.ToJson().StringToBytes();
        }

        /// <summary>
        /// 字节转对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="bytes"></param>
        /// <param name="encoding"></param>
        /// <returns></returns>
        public static T BytesToObject<T>(this byte[] bytes, Encoding encoding = null)
        {
            return bytes.ByteToString().ToObject<T>();
        }

        /// <summary>
        /// 字符串转换成MD5
        /// </summary>
        /// <param name="plainText"></param>
        /// <returns></returns>
        public static string ToMd5String(this string plainText)
        {
            using (MD5 md5 = MD5.Create())
            {
                byte[] inputBytes = Encoding.UTF8.GetBytes(plainText);
                byte[] hashBytes = md5.ComputeHash(inputBytes);

                StringBuilder sb = new StringBuilder();
                foreach (byte hashByte in hashBytes)
                {
                    sb.Append(hashByte.ToString("x2"));
                }
                return sb.ToString();
            }
        }


        /// <summary>
        /// 产生长度64位的小写唯一字符串
        /// </summary>
        /// <param name="plainText"></param>
        /// <returns></returns>
        public static string ToSHA256String(this string plainText)
        {
            using (SHA256 md5 = SHA256.Create())
            {
                byte[] inputBytes = Encoding.UTF8.GetBytes(plainText);
                byte[] hashBytes = md5.ComputeHash(inputBytes);

                StringBuilder sb = new StringBuilder();
                foreach (byte hashByte in hashBytes)
                {
                    sb.Append(hashByte.ToString("x2"));
                }
                return sb.ToString();
            }
        }
    }
}
